﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Nightwish.Controls.Tree;
using System.Diagnostics;
using System.Collections;
using System.Drawing.Design;
using System.Globalization;
using System.Windows.Forms.Design;
using System.IO;
using System.Collections.Specialized;

namespace Dzzzr
{
	public partial class MainForm : Form
	{
		/// <summary>
		/// Last focused tree
		/// </summary>
		TreeViewAdv lastFocusedTree = null;

		/// <summary>
		/// Current logined user
		/// </summary>
		protected User currentUser = null;
		/// <summary>
		/// Current logined user
		/// </summary>
		protected User CurrentUser
		{
			get
			{
				return currentUser;
			}
			set
			{
				currentUser = value;
				if (currentUser != null)
				{
					// update UI
					lblLogged.Text = "Logged: " + currentUser.ToString();

					// readonly
					treeMain.AllowDrop = !currentUser.IsReadOnly;
					
					mnuAdd.Visible = !currentUser.IsReadOnly;
					mnuEdit.Visible = !currentUser.IsReadOnly;
					mnuDelete.Visible = !currentUser.IsReadOnly;
					toolStrip.Visible = !currentUser.IsReadOnly;

					lnkTeamAddGame.Visible = !currentUser.IsReadOnly;
					lnkTeamAddUser.Visible = !currentUser.IsReadOnly;
					lnkTeamAddEntity.Visible = !currentUser.IsReadOnly;
					lnkTeamEdit.Visible = !currentUser.IsReadOnly;
					lnkUserEdit.Visible = !currentUser.IsReadOnly;
					lnkGameEdit.Visible = !currentUser.IsReadOnly;
					lnkEntityEdit.Visible = !currentUser.IsReadOnly;
					
					treeMain.ContextMenuStrip = !currentUser.IsReadOnly ? treeMain.ContextMenuStrip : null;
					treeEntity.ContextMenuStrip = !currentUser.IsReadOnly ? treeEntity.ContextMenuStrip : null;
				}
			}
		}

		/// <summary>
		/// Database context
		/// </summary>
		private MonitoringDBDataContext dataContext = null;
		/// <summary>
		/// Database context
		/// </summary>
		protected MonitoringDBDataContext DataContext
		{
			get
			{
				if (dataContext == null)
				{
					string user = string.Empty;
					string password = string.Empty;
					// ask login detailes
					using (LoginForm loginForm = new LoginForm())
					{
						if (loginForm.ShowDialog() == DialogResult.OK)
						{
							user = loginForm.txtLogin.Text;
							password = loginForm.txtPassword.Text;
						}
					}

					// check login
					if (user.Length == 0)
						throw new Exception("Need to login");

					// get user
					var users = (from u in DBDataContext.DataContext.Users
										where u.Login == user && u.Password == password
										select u);
					if (users.Count() != 1)
						throw new Exception("Login error");
					User loggedUser = users.First();
					IEnumerable<Team> teamForUser = null;
					if (loggedUser.IsAdmin)
						teamForUser = from Team in DBDataContext.DataContext.Teams select Team;
					else if (loggedUser.IsTeamAdmin || loggedUser.IsReadOnly)
						teamForUser = from Team in DBDataContext.DataContext.Teams where Team.Users.Contains(loggedUser) select Team;
					else
						throw new Exception("You have no rights");

					CurrentUser = loggedUser;
					dataContext = DBDataContext.DataContext;
					btnLogin.Visible = false;

					TeamBrowserModel mainModel = new TeamBrowserModel();
					mainModel.Init(teamForUser);
					treeMain.Model = mainModel;
					
					// set first node selected
					if (treeMain.NodeControls.Count > 0)
					{
						TreeNodeAdv topNode = null;
						if (treeMain.Root != null && treeMain.Root.Children.Count > 0)
							topNode = treeMain.Root.Children[0];
						treeMain.SelectedNode = topNode;
						if (topNode != null && topNode.CanExpand)
							topNode.IsExpanded = true;
					}
					else
					{
						// update tree selection
						treeMain_SelectionChanged(null, EventArgs.Empty);
					}
				}
				return dataContext;
			}
		}

		/// <summary>
		/// Constructor
		/// </summary>
		public MainForm()
		{
			InitializeComponent();

			// process icon event
			nodeMainIcon.GetIconImage = GetIconImageforMain;
			nodeEntityIcon.GetIconImage = GetIconImageforEntity;

			// add custom image binding
			Binding binding = new System.Windows.Forms.Binding("Image", this.entityBindingSource, "Photo", true);
			binding.Format += new ConvertEventHandler(imageBinding_BinaryToImage);
			picEntityImage.DataBindings.Add(binding);

			userBindingSource.DataSourceChanged += new EventHandler(userBindingSource_DataSourceChanged);
			entityBindingSource.DataSourceChanged += new EventHandler(entityBindingSource_DataSourceChanged);
		}

		/// <summary>
		/// Process data source change
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void userBindingSource_DataSourceChanged(object sender, EventArgs e)
		{
			lblUserLogin.Text = userBindingSource.DataSource == null ? string.Empty : (userBindingSource.DataSource as User).Description;
		}

		/// <summary>
		/// Process data source change
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void entityBindingSource_DataSourceChanged(object sender, EventArgs e)
		{
			pnlInfoEntityImage.Visible = !(entityBindingSource.DataSource == null
				|| (entityBindingSource.DataSource is Entity
					&& (entityBindingSource.DataSource as Entity).Photo == null)
				|| (entityBindingSource.DataSource is Entity
					&& (entityBindingSource.DataSource as Entity).Photo != null
					&& (entityBindingSource.DataSource as Entity).Photo.Length == 0));

			pnlInfoEntityOtherDescription.Visible = !(entityBindingSource.DataSource == null
				|| (entityBindingSource.DataSource is Entity
					&& (entityBindingSource.DataSource as Entity).Description == null)
				|| (entityBindingSource.DataSource is Entity
					&& (entityBindingSource.DataSource as Entity).Description != null
					&& (entityBindingSource.DataSource as Entity).Description.Length == 0));
		}

		/// <summary>
		/// Convert Binary to Image
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void imageBinding_BinaryToImage(object sender, ConvertEventArgs e)
		{
			if (e.DesiredType != typeof(Image))
				return;

			if (e.Value is System.Data.Linq.Binary)
			{
				using (MemoryStream ms = new MemoryStream((e.Value as System.Data.Linq.Binary).ToArray()))
				{
					if (ms.Length > 0)
					{
						ms.Seek(0, SeekOrigin.Begin);
						e.Value = new Bitmap(ms);
					}
				}
			}
		}

		/// <summary>
		/// Get icon for node
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		/// <returns></returns>
		protected Image GetIconImageforEntity(object sender, TreeViewAdvEventArgs e)
		{
			if (e.Node.Tag is Entity)
				return ImageforEntity(e.Node.Tag as Entity);
			return null;
		}

		/// <summary>
		/// get image for entity
		/// </summary>
		/// <param name="entity"></param>
		/// <returns></returns>
		protected Image ImageforEntity(Entity entity)
		{
			//if (entity.Photo != null && entity.Photo.Length > 0)
			//{
			//    using (MemoryStream ms = new MemoryStream(entity.Photo.ToArray()))
			//    {
			//        return new Bitmap(new Bitmap(ms), new Size(16, 16));
			//    }
			//}
			switch (entity.EntityTypeID)
			{
				case EntityType.Person:
					return imgEntityList.Images[0];
				case EntityType.Car:
					return imgEntityList.Images[1];
				case EntityType.Headquater:
					return imgEntityList.Images[2];
				case EntityType.Faked:
					return imgEntityList.Images[3];
			}
			return null;
		}

		/// <summary>
		/// Get icon for node
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		/// <returns></returns>
		protected Image GetIconImageforMain(object sender, TreeViewAdvEventArgs e)
		{
			if (e.Node.Tag is Entity)
				return GetIconImageforEntity(sender, e);
			else if (e.Node.Tag is Team)
				return imgEntityList.Images[4];
			else if (e.Node.Tag is User)
				return imgEntityList.Images[5];
			else if (e.Node.Tag is Game)
			{
				if (e.Node.CanExpand && e.Node.IsExpanded)
					return imgEntityList.Images[7];
				else
					return imgEntityList.Images[6];
			}
			else if (e.Node.Tag is GameEntity)
				return ImageforEntity((e.Node.Tag as GameEntity).Entity);
			return null;
		}

		/// <summary>
		/// Entry point
		/// </summary>
		[STAThread]
		static void Main()
		{
			Application.EnableVisualStyles();
			Application.DoEvents();

			MainForm f = new MainForm();
			f.ShowDialog();
		}

		/// <summary>
		/// Drag start
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeMain_ItemDrag(object sender, ItemDragEventArgs e)
		{
			if (CurrentUser != null && !CurrentUser.IsReadOnly)
			{
				TreeNodeAdv selectedNode = treeMain.SelectedNode;
				if (selectedNode.Tag is Team || selectedNode.Tag is Game || selectedNode.Tag is User)
					return;
				if (selectedNode.Tag is GameEntity)
				{
					DoDragDrop(selectedNode, DragDropEffects.Copy);
				}
			}
		}

		/// <summary>
		/// Drop item
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeMain_DragDrop(object sender, DragEventArgs e)
		{
			ProcessDragObject(false, e);
		}

		/// <summary>
		/// Test drop ability
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeMain_DragOver(object sender, DragEventArgs e)
		{
			ProcessDragObject(true, e);
		}

		/// <summary>
		/// Process dragging event
		/// </summary>
		/// <param name="testOrProcess">test drag</param>
		/// <param name="e"></param>
		protected void ProcessDragObject(bool testOrProcess, DragEventArgs e)
		{
			e.Effect = DragDropEffects.None;
			if (e.Data.GetDataPresent(typeof(TreeNodeAdv)) && treeMain.DropPosition.Node != null)
			{
				// carring node
				TreeNodeAdv newNode = (TreeNodeAdv)e.Data.GetData(typeof(TreeNodeAdv));
				// node to drop in
				TreeNodeAdv positionNode = (TreeNodeAdv)treeMain.DropPosition.Node;

				// check point inside node
				if (treeMain.DropPosition.Position == NodePosition.Inside)
				{
					// expand node if collapsed
					if (!treeMain.DropPosition.Node.IsExpanded && treeMain.DropPosition.Node.CanExpand)
					{
						treeMain.DropPosition.Node.IsExpanded = true;
						treeMain.EnsureVisible(treeMain.DropPosition.Node);
					}

					// check Entity
					if (newNode.Tag is Entity)
					{
						// dragging from entity tree
						Entity entity = (Entity)newNode.Tag;
						switch (entity.EntityTypeID)
						{
							case EntityType.Person:
							case EntityType.Car:
								{
									// check this Entity does not already present in this Game
									if (positionNode.Tag is Game
										&& !(from ge in (positionNode.Tag as Game).GameEntities where ge.ParentGameEntityID == null select ge).Contains( // check only in top level entities
											new GameEntity { EntityID = entity.ID }, new GameEntityComparerForDrop())
										&& entity.Team == (positionNode.Tag as Game).Team) // check same Team
									{
										if (testOrProcess)
										{
											e.Effect = e.AllowedEffect;
										}
										else
										{
											// create entity
											GameEntity newGameEntity = new GameEntity
											{
												Entity = entity,
												Game = positionNode.Tag as Game,
												GameRoleID = GameRole.Admin,
												Visible = true
											};

											// insert to db
											MonitoringDBDataContext db = DataContext;
											System.Data.Linq.Table<Dzzzr.GameEntity> gameEntities = db.GameEntities;
											gameEntities.InsertOnSubmit(newGameEntity);
											db.SubmitChanges();

											// update tree
											(treeMain.Model as TeamBrowserModel).FireNodesInserted(
												this,
												new TreeModelEventArgs(
													new TreePath(new object[] { (positionNode.Tag as Game).Team, positionNode.Tag as Game }),
													new int[] { gameEntities.Count() - 1 },
													new object[] { newGameEntity }));
										}
									}
									else if (positionNode.Tag is GameEntity
										&& (positionNode.Tag as GameEntity).EntityID != entity.ID // do not allow put to itself
										&& !(positionNode.Tag as GameEntity).GameEntities.Contains(
											new GameEntity { EntityID = entity.ID }, new GameEntityComparerForDrop())
										&& entity.Team == (positionNode.Tag as GameEntity).Game.Team) // check same Team
									{
										if (testOrProcess)
										{
											e.Effect = e.AllowedEffect;
										}
										else
										{
											// create entity
											GameEntity newGameEntity = new GameEntity
											{
												Entity = entity,
												Game = (positionNode.Tag as GameEntity).Game,
												GameRoleID = GameRole.Admin,
												GameEntity1 = positionNode.Tag as GameEntity,
												Visible = true
											};

											// insert to db
											MonitoringDBDataContext db = DataContext;
											System.Data.Linq.Table<Dzzzr.GameEntity> gameEntities = db.GameEntities;
											gameEntities.InsertOnSubmit(newGameEntity);
											db.SubmitChanges();

											// update tree
											TreeNodeAdv node = positionNode;
											ArrayList pathObjects = new ArrayList();
											while (node != null)
											{
												if (node.Tag != null)
													pathObjects.Insert(0, node.Tag);
												node = node.Parent;
											}
											(treeMain.Model as TeamBrowserModel).FireNodesInserted(
												this,
												new TreeModelEventArgs(
													new TreePath(pathObjects.ToArray()),
													new int[] { - 1 },
													new object[] { newGameEntity }));
										}
									}
								}
								break;
							case EntityType.Headquater:
							case EntityType.Faked:
								{
									// Headquater or Faked can be added only to game
									if (positionNode.Tag is Game)
									{
										// check this Entity does not already present in this Game
										if (!(positionNode.Tag as Game).GameEntities.Contains(
											new GameEntity { EntityID = entity.ID }, new GameEntityComparerForDrop())
											&& entity.Team == (positionNode.Tag as Game).Team) // check same Team
										{
											if (testOrProcess)
											{
												e.Effect = e.AllowedEffect;
											}
											else
											{
												// create entity
												GameEntity newGameEntity = new GameEntity
												{
													Entity = entity,
													Game = positionNode.Tag as Game,
													GameRoleID = GameRole.Admin,
													Visible = true
												};

												// insert to db
												MonitoringDBDataContext db = DataContext;
												System.Data.Linq.Table<Dzzzr.GameEntity> gameEntities = db.GameEntities;
												gameEntities.InsertOnSubmit(newGameEntity);
												db.SubmitChanges();

												// update tree
												(treeMain.Model as TeamBrowserModel).FireNodesInserted(
													this,
													new TreeModelEventArgs(
														new TreePath(new object[] { (positionNode.Tag as Game).Team, positionNode.Tag as Game }),
														new int[] { gameEntities.Count() - 1 },
														new object[] { newGameEntity }));
											}
										}
									}
								}
								break;
							default:
								return;
						}
					}
					else if (newNode.Tag is GameEntity)
					{
						// copy GameEntity from enother Game
						GameEntity gameEntity = newNode.Tag as GameEntity;

						// check this Entity does not already present in this Game
						if (positionNode.Tag is Game
							&& !(positionNode.Tag as Game).GameEntities.Contains(
								new GameEntity { EntityID = gameEntity.EntityID }, new GameEntityComparerForDrop())
								&& gameEntity.Game.Team == (positionNode.Tag as Game).Team) // check same Team
						{
							if (testOrProcess)
							{
								e.Effect = e.AllowedEffect;
							}
							else
							{
								// copy tree node
								CopyGameEntity(newNode, positionNode);
							}
						}
						else if (positionNode.Tag is GameEntity
							&& (positionNode.Tag as GameEntity).ID != gameEntity.ID // do not allow put to itself
							&& !(positionNode.Tag as GameEntity).GameEntities.Contains(
								new GameEntity { EntityID = gameEntity.EntityID }, new GameEntityComparerForDrop())
							&& gameEntity.Game.Team == (positionNode.Tag as GameEntity).Game.Team) // check same Team
						{
							if (testOrProcess)
							{
								e.Effect = e.AllowedEffect;
							}
							else
							{
								// copy tree node
								CopyGameEntity(newNode, positionNode);
							}
						}
					}
				}
			}
		}

		/// <summary>
		/// Copy tree node
		/// </summary>
		/// <param name="source"></param>
		/// <param name="dest"></param>
		protected void CopyGameEntity(TreeNodeAdv source, TreeNodeAdv dest)
		{
			// source
			GameEntity gameEntity = source.Tag as GameEntity;
			// new
			GameEntity newEntity = null;
			// copy all entities
			if (gameEntity != null)
			{
				if (dest.Tag is Game)
					newEntity = CopyGameEntity(gameEntity, null, dest.Tag as Game);
				else if (dest.Tag is GameEntity)
					newEntity = CopyGameEntity(gameEntity, dest.Tag as GameEntity, (dest.Tag as GameEntity).Game);

				if (newEntity != null)
				{
					// save DB
					MonitoringDBDataContext db = DataContext;
					db.SubmitChanges();

					// update tree
					TreeNodeAdv node = dest;
					ArrayList pathObjects = new ArrayList();
					while (node != null)
					{
						if (node.Tag != null)
							pathObjects.Insert(0, node.Tag);
						node = node.Parent;
					}
					// insert first, other wil be inserted automaticly
					(treeMain.Model as TeamBrowserModel).FireNodesInserted(
						this,
						new TreeModelEventArgs(
							new TreePath(pathObjects.ToArray()),
							new int[] { -1 },
							new object[] { newEntity }));
				}
			}
		}

		/// <summary>
		/// Copy GameEntity and all children
		/// </summary>
		/// <param name="source"></param>
		/// <param name="dest"></param>
		/// <param name="game"></param>
		/// <returns></returns>
		protected GameEntity CopyGameEntity(GameEntity source, GameEntity dest, Game game)
		{
			// create entity
			GameEntity newGameEntity = new GameEntity
			{
				Entity = source.Entity,
				Game = game,
				GameRoleID = GameRole.Admin,
				Visible = true
			};
			// add parent
			if (dest != null)
				newGameEntity.GameEntity1 = dest;

			// insert to db
			MonitoringDBDataContext db = DataContext;
			System.Data.Linq.Table<Dzzzr.GameEntity> gameEntities = db.GameEntities;
			gameEntities.InsertOnSubmit(newGameEntity);

			// copy child nodes
			foreach (GameEntity childSource in source.GameEntities)
			{
				CopyGameEntity(childSource, newGameEntity, game);
			}

			// return first node
			return newGameEntity;
		}

		/// <summary>
		/// Comparer for objects in list
		/// </summary>
		public class GameEntityComparerForDrop : IEqualityComparer<GameEntity>
		{
			/// <summary>
			/// Check for objects equasl
			/// </summary>
			/// <param name="x"></param>
			/// <param name="y"></param>
			/// <returns></returns>
			public bool Equals(GameEntity x, GameEntity y)
			{
				return x.EntityID == y.EntityID;
			}

			/// <summary>
			/// Object hash code
			/// </summary>
			/// <param name="obj"></param>
			/// <returns></returns>
			public int GetHashCode(GameEntity obj)
			{
				return obj.EntityID;
			}
		}

		/// <summary>
		/// Update team etities in another tree
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeMain_SelectionChanged(object sender, EventArgs e)
		{
			TreeNodeAdv selectedNode = treeMain.SelectedNode;

			while (selectedNode != null
				&& !(selectedNode.Tag is Team)
				&& selectedNode != null && selectedNode.Parent != null)
				selectedNode = selectedNode.Parent;

			if (!(selectedNode != null && treeEntity.Model != null && treeEntity.Model is EntityBrowserModel
				&& object.Equals((treeEntity.Model as EntityBrowserModel).Team, selectedNode.Tag)))
			{
				EntityBrowserModel entityModel = new EntityBrowserModel();
				if (selectedNode == null)
					entityModel.Init(null);
				else
					entityModel.Init(selectedNode.Tag as Team);
				treeEntity.Model = entityModel;
			}

			// update info
			ShowInfoForObject(treeMain.SelectedNode != null ? treeMain.SelectedNode.Tag : null);
		}

		/// <summary>
		/// Process selection change
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeEntity_SelectionChanged(object sender, EventArgs e)
		{
			// update info
			ShowInfoForObject(treeEntity.SelectedNode != null ? treeEntity.SelectedNode.Tag : null);
		}

		/// <summary>
		/// Start drag item
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeEntity_ItemDrag(object sender, ItemDragEventArgs e)
		{
			if (CurrentUser != null && !CurrentUser.IsReadOnly)
				DoDragDrop(treeEntity.SelectedNode, DragDropEffects.Copy);
		}

		/// <summary>
		/// Focus changed
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeMain_Enter(object sender, EventArgs e)
		{
			lastFocusedTree = treeMain;
		}

		/// <summary>
		/// Focus changed
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeEntity_Enter(object sender, EventArgs e)
		{
			lastFocusedTree = treeEntity;
		}

		/// <summary>
		/// Currently selected team
		/// </summary>
		protected Team SelectedTeam
		{
			get
			{
				TreeNodeAdv selectedNode = treeMain.SelectedNode;
				while (selectedNode != null
					&& !(selectedNode.Tag is Team)
					&& selectedNode != null && selectedNode.Parent != null)
					selectedNode = selectedNode.Parent;

				if (selectedNode == null)
					return null;
				return selectedNode.Tag as Team;
			}
		}

		#region Event handling
		/// <summary>
		/// Event handling
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnLogin_Click(object sender, EventArgs e)
		{
			try
			{
				// login
				Login();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handling
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuAddTeam_Click(object sender, EventArgs e)
		{
			try
			{
				// add Team
				AddTeam();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handling
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuAddUser_Click(object sender, EventArgs e)
		{
			try
			{
				// add user
				AddUser();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handling
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuAddGame_Click(object sender, EventArgs e)
		{
			try
			{
				// add Game
				AddGame();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handling
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuAddEntity_Click(object sender, EventArgs e)
		{
			try
			{
				// add Entity
				AddEntity();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuEdit_Click(object sender, EventArgs e)
		{
			try
			{
				// edit object
				EditObject();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuDelete_Click(object sender, EventArgs e)
		{
			try
			{
				if (lastFocusedTree == treeMain)
				{
					try
					{
						TreeNodeAdv selectedNode = treeMain.SelectedNode;
						if (selectedNode != null)
						{
							if (selectedNode.Tag is User)
							{
								User userToDelete = selectedNode.Tag as User;

								// ask before delete
								if (MessageBox.Show(string.Format("Delete user '{0}'?", userToDelete.Name), "Delete object", MessageBoxButtons.YesNo) == DialogResult.No)
									return;

								Team team = userToDelete.Team;

								MonitoringDBDataContext db = DataContext;
								System.Data.Linq.Table<Dzzzr.User> users = db.Users;
								users.DeleteOnSubmit(userToDelete);
								db.SubmitChanges();

								// update tree
								(treeMain.Model as TeamBrowserModel).FireNodesRemoved(
									this,
									new TreeModelEventArgs(new TreePath(new object[] { team }), new object[] { userToDelete }));
							}
							else if (selectedNode.Tag is Game)
							{
								Game gameToDelete = selectedNode.Tag as Game;
								
								// ask before delete
								if (MessageBox.Show(string.Format("Delete game '{0}'?", gameToDelete.Name), "Delete object", MessageBoxButtons.YesNo) == DialogResult.No)
									return;

								Team team = gameToDelete.Team;

								MonitoringDBDataContext db = DataContext;
								System.Data.Linq.Table<Dzzzr.Game> users = db.Games;
								users.DeleteOnSubmit(gameToDelete);
								db.SubmitChanges();

								// update tree
								(treeMain.Model as TeamBrowserModel).FireNodesRemoved(
									this,
									new TreeModelEventArgs(new TreePath(new object[] { team }), new object[] { gameToDelete }));
							}
							else if (selectedNode.Tag is Team)
							{
								Team teamToDelete = selectedNode.Tag as Team;

								// ask before delete
								if (MessageBox.Show(string.Format("Delete team '{0}'?", teamToDelete.Name), "Delete object", MessageBoxButtons.YesNo) == DialogResult.No)
									return;

								MonitoringDBDataContext db = DataContext;
								System.Data.Linq.Table<Dzzzr.Team> teams = db.Teams;
								teams.DeleteOnSubmit(teamToDelete);
								db.SubmitChanges();

								// update tree
								(treeMain.Model as TeamBrowserModel).FireNodesRemoved(
									this,
									new TreeModelEventArgs(TreePath.Empty, new object[] { teamToDelete }));
							}
							else if (selectedNode.Tag is GameEntity)
							{
								GameEntity gameEntityToDelete = selectedNode.Tag as GameEntity;

								// ask before delete
								if (MessageBox.Show(string.Format("Delete entity '{0}'?", gameEntityToDelete.Name), "Delete object", MessageBoxButtons.YesNo) == DialogResult.No)
									return;

								Game game = gameEntityToDelete.Game;

								MonitoringDBDataContext db = DataContext;
								System.Data.Linq.Table<Dzzzr.GameEntity> gameEntities = db.GameEntities;
								gameEntities.DeleteOnSubmit(gameEntityToDelete);
								db.SubmitChanges();

								// update tree
								TreeNodeAdv node = selectedNode.Parent;
								ArrayList pathObjects = new ArrayList();
								while (node != null)
								{
									if (node.Tag != null)
										pathObjects.Insert(0, node.Tag);
									node = node.Parent;
								}
								(treeMain.Model as TeamBrowserModel).FireNodesRemoved(
									this,
									new TreeModelEventArgs(
										new TreePath(pathObjects.ToArray()),
										new object[] { gameEntityToDelete }));
							}
						}
					}
					catch (Exception ex)
					{
						Debug.WriteLine(ex.ToString());
						MessageBox.Show(ex.ToString());
					}
				}
				else if (lastFocusedTree == treeEntity)
				{
					try
					{
						TreeNodeAdv selectedNode = treeEntity.SelectedNode;
						if (selectedNode != null && selectedNode.Tag is Entity)
						{
							Entity entity = selectedNode.Tag as Entity;

							// ask before delete
							if (MessageBox.Show(string.Format("Delete entity '{0}'?", entity.Name), "Delete object", MessageBoxButtons.YesNo) == DialogResult.No)
								return;

							MonitoringDBDataContext db = DataContext;
							System.Data.Linq.Table<Dzzzr.Entity> entities = db.Entities;
							entities.DeleteOnSubmit(entity);
							db.SubmitChanges();

							// update tree
							(treeEntity.Model as EntityBrowserModel).FireNodesRemoved(
								this,
								new TreeModelEventArgs(TreePath.Empty, new object[] { entity }));
						}
					}
					catch (Exception ex)
					{
						Debug.WriteLine(ex.ToString());
						MessageBox.Show(ex.ToString());
					}
				}
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event processing
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void mnuExit_Click(object sender, EventArgs e)
		{
			Application.Exit();
		}
		#endregion

		#region Command processing
		/// <summary>
		/// Perform login
		/// </summary>
		protected void Login()
		{
			dataContext = null;
			DBDataContext.DataContext = null;
			MonitoringDBDataContext db = DataContext;
		}

		/// <summary>
		/// Add Team
		/// </summary>
		protected void AddTeam()
		{
			Team newTeam = new Team();

			// show params
			DetailForm ud = new DetailForm();
			ud.Text = "New Team detailes";
			ud.propertyGrid.SelectedObject = newTeam;
			if (ud.ShowDialog() == DialogResult.OK)
			{
				// add user to db
				MonitoringDBDataContext db = DataContext;
				System.Data.Linq.Table<Dzzzr.Team> teams = db.Teams;
				teams.InsertOnSubmit(newTeam);
				db.SubmitChanges();

				// update tree
				(treeMain.Model as TeamBrowserModel).FireNodesInserted(
					this,
					new TreeModelEventArgs(
						TreePath.Empty,
						new int[] { teams.Count() - 1 },
						new object[] { newTeam }));
			}
		}
		
		/// <summary>
		/// Add new user
		/// </summary>
		protected void AddUser()
		{
			TreeNodeAdv selectedNode = treeMain.SelectedNode;
			while (selectedNode != null
				&& !(selectedNode.Tag is Team)
				&& selectedNode != null && selectedNode.Parent != null)
				selectedNode = selectedNode.Parent;

			if (selectedNode != null && selectedNode.Tag is Team)
			{
				Team team = selectedNode.Tag as Team;
				if (team != null)
				{
					User newUser = new User();
					newUser.Team = team;
					newUser.Login = string.Empty;
					newUser.Password = string.Empty;

					// show params
					DetailForm ud = new DetailForm();
					ud.Text = "New User detailes";
					ud.propertyGrid.SelectedObject = newUser;
					if (ud.ShowDialog() == DialogResult.OK)
					{
						// add user to db
						MonitoringDBDataContext db = DataContext;
						System.Data.Linq.Table<Dzzzr.User> users = db.Users;
						users.InsertOnSubmit(newUser);
						db.SubmitChanges();

						// update tree
						(treeMain.Model as TeamBrowserModel).FireNodesInserted(
							this,
							new TreeModelEventArgs(
								new TreePath(team),
								new int[] { team.Users.Count - 1 },
								new object[] { newUser }));
					}
				}
			}
		}
		
		/// <summary>
		/// Add Game
		/// </summary>
		protected void AddGame()
		{
			TreeNodeAdv selectedNode = treeMain.SelectedNode;
			while (selectedNode != null
				&& !(selectedNode.Tag is Team)
				&& selectedNode != null && selectedNode.Parent != null)
				selectedNode = selectedNode.Parent;

			if (selectedNode != null && selectedNode.Tag is Team)
			{
				Team team = selectedNode.Tag as Team;
				if (team != null)
				{
					Game newGame = new Game();
					newGame.Team = team;
					newGame.Name = "Game name";

					// show params
					DetailForm ud = new DetailForm();
					ud.Text = "New Game detailes";
					ud.propertyGrid.SelectedObject = newGame;
					if (ud.ShowDialog() == DialogResult.OK)
					{
						// add user to db
						MonitoringDBDataContext db = DataContext;
						System.Data.Linq.Table<Dzzzr.Game> games = db.Games;
						games.InsertOnSubmit(newGame);
						db.SubmitChanges();

						// update tree
						(treeMain.Model as TeamBrowserModel).FireNodesInserted(
							this,
							new TreeModelEventArgs(
								new TreePath(team),
								new int[] { team.Users.Count + team.Games.Count - 1 },
								new object[] { newGame }));
					}
				}
			}
		}
		
		/// <summary>
		/// Add Entity
		/// </summary>
		protected void AddEntity()
		{
			TreeNodeAdv selectedNode = treeMain.SelectedNode;
			while (selectedNode != null
				&& !(selectedNode.Tag is Team)
				&& selectedNode != null && selectedNode.Parent != null)
				selectedNode = selectedNode.Parent;

			if (selectedNode != null && selectedNode.Tag is Team)
			{
				Team team = selectedNode.Tag as Team;
				if (team != null)
				{
					Entity newEntity = new Entity();
					newEntity.Team = team;
					newEntity.Name = "Entity name";
					newEntity.EntityTypeID = EntityType.Person;

					// show params
					DetailForm ud = new DetailForm();
					ud.Text = "Entity detailes";
					ud.propertyGrid.SelectedObject = newEntity;
					if (ud.ShowDialog() == DialogResult.OK)
					{
						// add user to db
						MonitoringDBDataContext db = DataContext;
						System.Data.Linq.Table<Dzzzr.Entity> entitys = db.Entities;
						entitys.InsertOnSubmit(newEntity);
						db.SubmitChanges();

						// update tree
						var count = (from en in team.Entities where en.EntityTypeID <= newEntity.EntityTypeID select en).Count();
						(treeEntity.Model as EntityBrowserModel).FireNodesInserted(
							this,
							new TreeModelEventArgs(
								TreePath.Empty,
								new int[] { Convert.ToInt32(count) - 1 },
								new object[] { newEntity }));
					}
				}
			}
		}

		/// <summary>
		/// Edit object
		/// </summary>
		protected void EditObject()
		{
			if (lastFocusedTree == treeMain)
			{
				TreeNodeAdv selectedNode = treeMain.SelectedNode;
				if (selectedNode != null)
				{

					// show params
					DetailForm ud = new DetailForm();
					ud.Text = "Edit detailes";
					ud.propertyGrid.SelectedObject = selectedNode.Tag;
					if (ud.ShowDialog() == DialogResult.OK)
					{
						// add user to db
						MonitoringDBDataContext db = DataContext;
						db.SubmitChanges();

						// update tree
						(treeMain.Model as TeamBrowserModel).FireNodesChanged(
							this,
							new TreeModelEventArgs(
								TreePath.Empty,
								new object[] { selectedNode.Tag }));
						treeMain.BeginUpdate();
						treeMain.EndUpdate();
						treeEntity.BeginUpdate();
						treeEntity.EndUpdate();
						ShowInfoForObject(null);
						ShowInfoForObject(selectedNode.Tag);
					}
					else
					{
						MonitoringDBDataContext db = DataContext;
						// reject changes
					}
				}
			}
			else if (lastFocusedTree == treeEntity)
			{
				TreeNodeAdv selectedNode = treeEntity.SelectedNode;
				if (selectedNode != null && selectedNode.Tag is Entity)
				{
					Entity entity = selectedNode.Tag as Entity;
					entity.PropertyChanged += new PropertyChangedEventHandler(entity_PropertyChanged);

					// show params
					DetailForm ud = new DetailForm();
					ud.Text = "Entity detailes";
					ud.propertyGrid.SelectedObject = entity;
					if (ud.ShowDialog() == DialogResult.OK)
					{
						MonitoringDBDataContext db = DataContext;
						db.SubmitChanges();

						// update tree
						(treeEntity.Model as EntityBrowserModel).FireNodesChanged(
							this,
							new TreeModelEventArgs(TreePath.Empty, new object[] { entity }));
						treeMain.BeginUpdate();
						treeMain.EndUpdate();
						treeEntity.BeginUpdate();
						treeEntity.EndUpdate();
						ShowInfoForObject(null);
						ShowInfoForObject(selectedNode.Tag);
					}
					else
					{
						MonitoringDBDataContext db = DataContext;
						// reject changes

					}
					entity.PropertyChanged -= new PropertyChangedEventHandler(entity_PropertyChanged);
				}
			}
		}

		void entity_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "EntityType")
			{
				// mark to delete
				DataContext.EntityAttributes.DeleteAllOnSubmit((sender as Entity).EntityAttributes);
				// set colection empty
				(sender as Entity).EntityAttributes.Clear();
				//(sender as Entity).EntityAttributes = null;
			}
		}

		#endregion

		#region Status bar
		#endregion

		#region Info panel
		/// <summary>
		/// Show object info
		/// </summary>
		/// <param name="o"></param>
		protected void ShowInfoForObject(object o)
		{
			teamBindingSource.DataSource = o as Team == null ? new Team() : o as Team;
			pnlInfoTeam.Visible = o is Team;
			pnlInfoTeam.Dock = DockStyle.Fill;

			Entity entity = o as Entity == null ? (o as GameEntity == null ? null : (o as GameEntity).Entity) : o as Entity;
			entityBindingSource.DataSource = entity ?? new Entity();
			pnlInfoEntity.Visible = entity is Entity;
			pnlInfoEntity.Dock = DockStyle.Fill;

			userBindingSource.DataSource = o as User ?? new User();
			pnlInfoUser.Visible = o is User;
			pnlInfoUser.Dock = DockStyle.Fill;

			gameBindingSource.DataSource = o as Game ?? new Game();
			pnlInfoGame.Visible = o is Game;
			pnlInfoGame.Dock = DockStyle.Fill;
		}

		/// <summary>
		/// Event handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void lnkTeamAddUser_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			try
			{
				// add User
				AddUser();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void lnkTeamAddGame_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			try
			{
				// add Game
				AddGame();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void lnkTeamAddEntity_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			try
			{
				// add Entity
				AddEntity();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		/// <summary>
		/// Event handler
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void lnkTeamEdit_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			try
			{
				// edit object
				EditObject();
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.ToString());
				MessageBox.Show(ex.ToString());
			}
		}

		#endregion
	}
}

// TODO: отмена изменений в объекте
// TODO: как очистить полностью дочернюю коллекцию?
// TODO: 
// TODO: 



